﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XSTDZ.ERP.Application.DataContracts;
using AutoMapper;
using XSTDZ.ERP.Domain.Models;
using XSTDZ.ERP.Core.Repositories;
using XSTDZ.ERP.Core.Generator;
using XSTDZ.ERP.Core.Specifications;
using System.Linq.Expressions;

namespace XSTDZ.ERP.Application.Implements
{
    public class ProductInServiceImpl : ApplicationServiceBase, IProductInService
    {
        IRepository<ProductInBill> _productRepository;
        IRepository<ProductInBillDetail> _productDetailRepository;
        IRepository<Stock> _stockRepository;
        public ProductInServiceImpl(IRepositoryContext repositoryContext, IRepository<ProductInBill> productRepository, IRepository<ProductInBillDetail> productDetailRepository, IRepository<Stock> stockRepository)
            : base(repositoryContext)
        {
            this._productRepository = productRepository;
            this._productDetailRepository = productDetailRepository;
            this._stockRepository = stockRepository;
        }
        #region 入库订单

        public Guid AddProductInBill(ProductInBillDto productInBillDto)
        {
            var productInBill = Mapper.Map<ProductInBillDto, ProductInBill>(productInBillDto);
            productInBill.Init();
            AddProductInBill(productInBill);
            return productInBill.Id;
        }
        public Guid AddProductInBill(Guid productInBillId, IEnumerable<ProductInBillDetailDto> productInBillDetailDtos)
        {
            var productInBill = this._productRepository.GetByKey(productInBillId);
            var productInBillDetails = Mapper.Map<IEnumerable<ProductInBillDetailDto>, IEnumerable<ProductInBillDetail>>(productInBillDetailDtos);
            productInBill.Init().AddChildren(productInBillDetails);
            AddProductInBill(productInBill);
            return productInBill.Id;
        }

        public void AddProductInBill(IList<ProductInBill> productInBills)
        {
            productInBills.Each(t => {
                t.Init();
                t.ProductInBillDetails.Each(m => m.Init());
            });
            this._productRepository.Add(productInBills);
        }

        public Guid AddProductInBill(ProductInBillDto productInBillDto, IEnumerable<ProductInBillDetailDto> productInBillDetailDtos)
        {
            var productBill = _productRepository.Exists(p => p.Id == productInBillDto.ID);
            if (!productBill)
            {
                var productInBill = Mapper.Map<ProductInBillDto, ProductInBill>(productInBillDto);
                var productInBillDetails = Mapper.Map<IEnumerable<ProductInBillDetailDto>, IEnumerable<ProductInBillDetail>>(productInBillDetailDtos);
                productInBill.Init().ClearChildrenAll().AddChildren(productInBillDetails);
               
              //var stocks=  GetStockDto(productInBillDetailDtos, productInBill.StorehouseID);//添加库存
              //  UpdateStock(stocks);

                AddProductInBill(productInBill);
                return productInBill.Id;
            }
            else
            {
               return UpdateProductInBill(productInBillDto, productInBillDetailDtos);
            }
            
        }
        public void UpdateProductInBill(ProductInBillDto productInBillDto)
        {
            var productInBill = Mapper.Map<ProductInBillDto, ProductInBill>(productInBillDto);
            UpdateProductInBill(productInBill);
        }
        public void UpdateProductInBill(Guid productInBillId, IEnumerable<ProductInBillDetailDto> productInBillDetailDtos)
        {
            var productInBill = this._productRepository.GetByKey(productInBillId);
            var productInBillDetails = Mapper.Map<IEnumerable<ProductInBillDetailDto>, IEnumerable<ProductInBillDetail>>(productInBillDetailDtos);
            productInBill.Init().ClearChildrenAll().AddChildren(productInBillDetails);
            UpdateProductInBill(productInBill);
        }

       
        public void ConfirmUpdateStock(Guid billId)
        {
            var pinBill = this._productRepository.GetByKey(billId);
            if (pinBill.BillState != 1)
            {

                IList<Stock> stockDtos = new List<Stock>();//库存数据

                foreach (var p in pinBill.ProductInBillDetails)
                {
                    var stock = new Stock
                    {
                        StorehouseID = pinBill.StorehouseID,
                        ProductID = p.ProductID
                    };
                    stock.StockCount = p.InlCount;//没有更新品种
                    stockDtos.Add(stock);

                }
                pinBill.BillState = 1;
                this._productRepository.Update(pinBill);
                UpdateStock(stockDtos);//更新库存
                this.Context.Commit();
            }
        }
     
        public Guid UpdateProductInBill(ProductInBillDto productInBillDto, IEnumerable<ProductInBillDetailDto> productInBillDetailDtos)
        {
            var pinBill = this._productRepository.GetByKey(productInBillDto.ID);
           
            productInBillDto.CreateTime = pinBill.CreateTime;
            pinBill.UpdateDate = DateTime.Now;
            pinBill = Mapper.Map(productInBillDto, pinBill);

            IList<Stock> stockDtos = new List<Stock>();//库存数据

            var productlDetails = Mapper.Map<IEnumerable<ProductInBillDetailDto>, IEnumerable<ProductInBillDetail>>(productInBillDetailDtos);

            foreach (var p in pinBill.ProductInBillDetails)
            {
                foreach (var pdto in productInBillDetailDtos)
                {
                    if (p.Id == pdto.ID)
                    {

                        #region 先满足库存
                        var stock = new Stock
                        {
                            StorehouseID = pinBill.StorehouseID,
                            ProductID = pdto.ProductID
                            //    StockCount =pdto.InlCount- p.InlCount
                        };

                        if (p.ProductID != pdto.ProductID) ////更新明细时，修改了商品（品种），可能修改后的没有库存，需要新增
                        {
                            stock.StockCount = pdto.InlCount;// 把新数据写入数据库
                            stockDtos.Add(stock);//进行添加


                            stockDtos.Add(new Stock
                            {
                                StorehouseID = pinBill.StorehouseID,
                                ProductID = p.ProductID, //需要进行更新之前的数据行
                                StockCount = -p.InlCount //需要新增的新品种数量
                            });
                        }
                        else
                        {
                            stock.StockCount = pdto.InlCount - p.InlCount;//没有更新品种
                            stockDtos.Add(stock);
                        }
                        #endregion

                        p.InlCount = pdto.InlCount;
                        p.ProductID = pdto.ProductID;
                        p.Remarks = pdto.Remarks;
                        p.ShelfNumber = pdto.ShelfNumber;
                        p.ProductInfo = null;

                        break;
                    }
                }
            }
            //这部分是新增的明细行，需要进行写入数据库
            var insertItems=new List<ProductInBillDetail>();
            if (pinBill.ProductInBillDetails != null && pinBill.ProductInBillDetails.Count() != 0)
            {
                productlDetails.Each(p =>
                {
                    var tag = false;
                    pinBill.ProductInBillDetails.Each(i =>
                    {
                        if (p.Id == i.Id)
                        {
                            tag = true;
                        }
                    });
                    if (!tag)
                    {
                        insertItems.Add(p);
                    }

                });
            }
            else
            {
                insertItems = productlDetails.ToList();
            }
           
            if (insertItems.Count() != 0)
            {
                this._productDetailRepository.Add(insertItems);

                var stocks = GetStockDto(insertItems, productInBillDto.StorehouseID);//添加库存
              //  stocks = stocks.Concat(stockInsertItems.ToList()).ToList();
              stockDtos = stockDtos.Concat(stocks).ToList();//
             
            }
            this._productRepository.Update(pinBill);

          //  UpdateStock(stockDtos);//更新库存
            this.Context.Commit();
            return pinBill.Id;
        }
     
        public void UpdateProductInBillDetail(Guid productInBillId, IEnumerable<ProductInBillDetailDto> productInBillDetailDtos)
        {
            var productlDetails = Mapper.Map<IEnumerable<ProductInBillDetailDto>, IEnumerable<ProductInBillDetail>>(productInBillDetailDtos);
            this._productDetailRepository.AddOrUpdate(productlDetails);
            this.Context.Commit();
          
        }
        public void ConvertProductInBillDeleteState(Guid productInBillId)
        {
            var itemIds = _productRepository.GetByKey(productInBillId).ProductInBillDetails.Select(p => p.Id).ToList().AsEnumerable();
            ConvertProductDelete(productInBillId, itemIds, true);
        }
      
        public ProductInBillDto GetProductInBill(Guid productInBillId)
        {
            var productInBill = this._productRepository.GetByKey(productInBillId);
            productInBill.WareHourse= productInBill.WareHourse?? new Storehouse(); 
            var billDto= Mapper.Map<ProductInBill, ProductInBillDto>(productInBill);
            return billDto;
        }

        public IEnumerable<ProductInBillDto> GetProductInBills(int pageIndex, int pageSize)
        {
          
            var orderby = new OrderByParameter<ProductInBill>(m =>m.CreateTime, SortOrder.Descending);

            var productInBills = this._productRepository.GetAll(pageIndex, pageSize, new[] { orderby });
            productInBills.Each(t => { t.WareHourse = t.WareHourse ?? new Storehouse(); });
            return Mapper.Map<IEnumerable<ProductInBill>, IEnumerable<ProductInBillDto>>(productInBills);
        }
        public IEnumerable<ProductInBillDto> GetProductInBills(out int recordCount, int pageIndex, int pageSize, string orgCode)
        {
            recordCount = 0;
            if (string.IsNullOrEmpty(orgCode))
            {
                return GetProductInBills(pageIndex, pageSize);
            }
         var   spec = Specification<ProductInBill>.Eval(t => t.SourceOrg.Code == orgCode);
            var orderby = new OrderByParameter<ProductInBill>(m => m.CreateTime, SortOrder.Descending);

            var eagerLoadingProperties = new List<Expression<Func<ProductInBill, dynamic>>>();
            eagerLoadingProperties.Add(m => m.SourceOrg);

            var productInBills = this._productRepository.FindAllQueryWithCount(out recordCount, spec, pageIndex, pageSize, new[] { orderby }, eagerLoadingProperties.ToArray())
                .ToList();
            productInBills.Each(t => { t.WareHourse = t.WareHourse ?? new Storehouse(); });
            return Mapper.Map<IEnumerable<ProductInBill>, IEnumerable<ProductInBillDto>>(productInBills);
        }

        public void ConvertProductInBillDeleteState(Guid productInBillId, IEnumerable<Guid> productInBillDetailIds)
        {
            ConvertProductDelete(productInBillId, productInBillDetailIds, false);
        }
        private void ConvertProductDelete(Guid productInBillId, IEnumerable<Guid> productInBillDetailIds, bool isAll)
        {
            var productInBill = this._productRepository.GetByKey(productInBillId);
            var productBillItemIds = productInBill.ProductInBillDetails.Where(p => productInBillDetailIds.ToArray().Contains(p.Id));
            if (isAll) {
                productInBill.SetDeleteState();
            }
            productInBill.SetChildrenDeleteState(productBillItemIds);
            UpdateProductInBill(productInBill);
        }
        #endregion
        #region 入库订单明细
        public void AddProductInBillDetail(Guid productInBillId, ProductInBillDetailDto productInBillDetailDto)
        {
           var productInBill = this._productRepository.GetByKey(productInBillId);
           var productInBillDetail = Mapper.Map<ProductInBillDetailDto, ProductInBillDetail>(productInBillDetailDto);
           productInBillDetail.Init();
           productInBill.AddChild(productInBillDetail);
           this._productRepository.Update(productInBill);
           this.Context.Commit();
        }


        public ProductInBillDetailDto GetProductInBillDetail(Guid productInBillDetailId)
        {
            var productInBillDetail = this._productRepository.Get(p => p.ProductInBillDetails.Count(d => d.Id == productInBillDetailId) > 0)
                .ProductInBillDetails.Where(p => p.Id == productInBillDetailId).FirstOrDefault();
            return Mapper.Map<ProductInBillDetail, ProductInBillDetailDto>(productInBillDetail);
        }

        public IEnumerable<ProductInBillDetailDto> GetProductInBillDetails(Guid productInBillId)
        {
            var productInBillDetail = this._productRepository.Get(p => p.Id == productInBillId).ProductInBillDetails;
            return Mapper.Map < IEnumerable<ProductInBillDetail>, IEnumerable<ProductInBillDetailDto>>(productInBillDetail);
        }
        #endregion
        #region 私有方法
        private void AddProductInBill(ProductInBill productInBill)
        {
            this._productRepository.Add(productInBill);
            this.Context.Commit();
        }
        private void UpdateProductInBill(ProductInBill productInBill)
        {
            this._productRepository.AddOrUpdate(productInBill);
            this.Context.Commit();
        }
        #endregion
        #region 更新库存


        private void UpdateStock(IList<Stock> stockDtos)
        {
            StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
            stockServiceImpl.UpdateStock(stockDtos);//更新库存
        }
        /// <summary>
        /// 获得新增的库存
        /// </summary>
        /// <returns></returns>
        private IList<Stock> GetStockDto(IEnumerable<ProductInBillDetailDto> detailitems, Guid wareHourseId)
        {
            var stocks = new List<Stock>();
            if (detailitems != null && detailitems.Count() != 0)
            {
                detailitems.Each(p =>
                {
                    stocks.Add(new Stock
                    {
                        StorehouseID = wareHourseId,
                        ProductID = p.ProductID,
                        StockCount = p.InlCount
                    });
                });
            }

            return stocks;
        }
        private IList<Stock> GetStockDto(IEnumerable<ProductInBillDetail> detailitems, Guid wareHourseId)
        {
            var stocks = new List<Stock>();
            if (detailitems != null && detailitems.Count() != 0)
            {
                detailitems.Each(p =>
                {
                    stocks.Add(new Stock
                    {
                        StorehouseID = wareHourseId,
                        ProductID = p.ProductID,
                        StockCount = p.InlCount
                    });
                });
            }

            return stocks;
        }
        #endregion
        #region 导入收货确认的发货单
        public void ImportConfirm(IEnumerable<Guid> deliveryIds)
        { 
     
        }
        #endregion
        public string GetMaxBillNo()
        {
            var orderby = new OrderByParameter<ProductInBill>(m => m.CreateTime, SortOrder.Descending);
            var billNo = this._productRepository.GetAll(1, 1, new[] { orderby }).FirstOrDefault();
            return billNo == null ? string.Empty : billNo.ProductInBillNo;
        }
    }
}
